package com.poi.dependency;
import org.apache.poi.xwpf.usermodel.XWPFDocument; 
import org.apache.poi.xwpf.usermodel.XWPFParagraph; 
import org.apache.poi.xwpf.usermodel.XWPFTable; 
import org.apache.poi.xwpf.usermodel.XWPFTableCell; 
import org.apache.poi.xwpf.usermodel.XWPFTableRow; 
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBookmark; 
import java.util.HashMap; 
import java.util.Iterator; 
import java.util.List; 
import java.util.Collection; 
import java.util.Set; 
import org.w3c.dom.NamedNodeMap; 
import org.w3c.dom.Node; 

/**
 * @author eastmelon
 *
 */
public class BookMarks {
	  
		/** 保存Word文件中定义的标签  **/
	    private HashMap<String, BookMark> _bookmarks = null; 
	    
	    /** 
	     * 构造函数，用以分析文档，解析出所有的标签
	     * 
	     * @param document  Word OOXML document instance. 
	     */ 
	    public BookMarks(XWPFDocument document) { 

	        //初始化标签缓存
	        this._bookmarks = new HashMap<String, BookMark>(); 
	        
	        // 首先解析文档普通段落中的标签 
	        this.procParaList(document.getParagraphs()); 

	        //利用繁琐的方法，从所有的表格中得到得到标签，处理比较原始和简单
	        List<XWPFTable> tableList = document.getTables(); 
	        
	        for (XWPFTable table : tableList) { 
	        	//得到表格的列信息
	        	List<XWPFTableRow> rowList = table.getRows(); 
	            for (XWPFTableRow row : rowList){ 
	            	//得到行中的列信息
	            	List<XWPFTableCell> cellList = row.getTableCells(); 
	                for (XWPFTableCell cell : cellList) { 
	                	//逐个解析标签信息
	                    //this.procParaList(cell.getParagraphs(), row);
	                	this.procParaList(cell);
	                } 
	            } 
	        } 
	    } 

	    
	    /**
	     * 根据标签名称，获得标签的相关定义，如果不存在，则返回空
	     * @param bookmarkName   标签名称
	     * @return    返回封装好的对象
	     */
	    public BookMark getBookmark(String bookmarkName) { 
	        BookMark bookmark = null; 
	        if(this._bookmarks.containsKey(bookmarkName)) { 
	            bookmark = this._bookmarks.get(bookmarkName); 
	        } 
	        return   bookmark; 
	    } 
	    
	    /** 
	     * 得到所有的标签信息集合
	     * 
	     * @return 缓存的标签信息集合 
	     */ 
	    public Collection<BookMark> getBookmarkList() { 
	        return(this._bookmarks.values()); 
	    } 
	    
	    /** 
	     * 返回文档中的标签名称迭代器
	     * @return  由Map KEY 转换的迭代器
	     */
	    public Iterator<String> getNameIterator() { 
	        return(this._bookmarks.keySet().iterator()); 
	    } 
	    

	    private void procParaList(XWPFTableCell cell){
	    	List<XWPFParagraph> paragraphList = cell.getParagraphs();
	    	
	    	for(XWPFParagraph paragraph : paragraphList){
	    		//得到段落中的标签标记
	        	List<CTBookmark> bookmarkList = paragraph.getCTP().getBookmarkStartList();
	        	for (CTBookmark bookmark : bookmarkList ) {
	        		this._bookmarks.put(bookmark.getName(),
	        				new BookMark(bookmark, paragraph, cell));
	        	}
	    	}
	    }
	    /**
	     * 解析表格中的标签
	     * @param paragraphList   传入的段落列表
	     * @param tableRow   对应的表格行对象 
	     */
	    private void procParaList(List<XWPFParagraph> paragraphList, XWPFTableRow tableRow) { 

	        NamedNodeMap attributes = null; 
	        Node colFirstNode = null; 
	        Node colLastNode = null; 
	        int firstColIndex = 0; 
	        int lastColIndex = 0; 
	        
	        //循环判断，解析段落中的标签
	        for (XWPFParagraph paragraph : paragraphList) { 
	        	//得到段落中的标签标记
	        	List<CTBookmark> bookmarkList = paragraph.getCTP().getBookmarkStartList(); 

	            for (CTBookmark bookmark : bookmarkList ) { 
	                // With a bookmark in hand, test to see if the bookmarkStart tag 
	                // has w:colFirst or w:colLast attributes. If it does, we are 
	                // dealing with a bookmarked table cell. This will need to be 
	                // handled differnetly - I think by an different concrete class 
	                // that implements the Bookmark interface!! 
	                attributes = bookmark.getDomNode().getAttributes(); 
	                if(attributes != null) { 

	                    // Get the colFirst and colLast attributes. If both - for 
	                    // now - are found, then we are dealing with a bookmarked 
	                    // cell. 
	                    colFirstNode = attributes.getNamedItem("w:colFirst"); 
	                    colLastNode = attributes.getNamedItem("w:colLast"); 
	                    if(colFirstNode != null && colLastNode != null) { 
	                    	
	                        // Get the index of the cell (or cells later) from them. 
	                        // First convefrt the String values both return to primitive 
	                        // int value. TO DO, what happens if there is a 
	                        // NumberFormatException. 
	                        firstColIndex = Integer.parseInt(colFirstNode.getNodeValue()); 
	                        lastColIndex = Integer.parseInt(colLastNode.getNodeValue()); 
	                        // if the indices are equal, then we are dealing with a# 
	                        // cell and can create the bookmark for it. 
	                        if(firstColIndex == lastColIndex) { 
	                            this._bookmarks.put(bookmark.getName(), 
	                                new BookMark(bookmark, paragraph, 
	                                    tableRow.getCell(firstColIndex))); 
	                        } 
	                        else { 
	                            System.out.println("This bookmark " + bookmark.getName() + 
	                                    " identifies a number of cells in the " 
	                                    + "table. That condition is not handled yet."); 
	                        } 
	                    } 
	                    else { 
	                        this._bookmarks.put(bookmark.getName(), 
	                        new BookMark(bookmark, paragraph,tableRow.getCell(1))); 
	                    } 
	                } 
	                else { 
	                    this._bookmarks.put(bookmark.getName(), 
	                        new BookMark(bookmark, paragraph,tableRow.getCell(1))); 
	                } 
	            } 
	        } 
	    } 
	    
	    /**
	     * 解析普通段落中的标签
	     * @param paragraphList  传入的段落
	     */
	    private void procParaList(List<XWPFParagraph> paragraphList) { 

	        for (XWPFParagraph paragraph : paragraphList) { 
	        	List<CTBookmark>  bookmarkList = paragraph.getCTP().getBookmarkStartList(); 
	            //循环加入标签
	            for (CTBookmark bookmark : bookmarkList) { 
	                this._bookmarks.put(bookmark.getName(), 
	                        new BookMark(bookmark, paragraph)); 
	            } 
	        } 
	    } 
}
